package yunjiao.javatutorials.guava.concurrent.timed;

import java.util.Comparator;
import java.util.Date;
import java.util.PriorityQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 任务调度器
 *
 * @author yangyunjiao
 */
public class TimedTaskScheduler {
    private final Lock lock = new ReentrantLock();
    private final TimedCondition taskCondition;
    private final PriorityQueue<ScheduledTask> taskQueue;

    public TimedTaskScheduler() {
        this.taskCondition = new TimedCondition(lock.newCondition());
        this.taskQueue = new PriorityQueue<>(Comparator.comparing(ScheduledTask::getExecuteTime));
    }

    public void schedule(Runnable task, long delay, TimeUnit unit) {
        lock.lock();
        try {
            long executeTime = System.currentTimeMillis() + unit.toMillis(delay);
            taskQueue.offer(new ScheduledTask(task, executeTime));
            taskCondition.signal();
            System.out.println("任务已调度，执行时间: " + new Date(executeTime));
        } finally {
            lock.unlock();
        }
    }

    public void start() {
        Thread schedulerThread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    lock.lock();
                    try {
                        if (taskQueue.isEmpty()) {
                            // 没有任务，等待新任务
                            taskCondition.await();
                        } else {
                            ScheduledTask nextTask = taskQueue.peek();
                            long now = System.currentTimeMillis();
                            long delay = nextTask.getExecuteTime() - now;

                            if (delay <= 0) {
                                // 执行任务
                                taskQueue.poll();
                                executeTask(nextTask.getTask());
                            } else {
                                // 等待到任务执行时间
                                boolean triggered = taskCondition.await(delay, TimeUnit.MILLISECONDS);
                                if (!triggered) {
                                    // 超时，执行任务
                                    taskQueue.poll();
                                    executeTask(nextTask.getTask());
                                }
                            }
                        }
                    } finally {
                        lock.unlock();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });

        schedulerThread.start();
    }

    private void executeTask(Runnable task) {
        try {
            task.run();
            System.out.println("任务执行完成");
        } catch (Exception e) {
            System.err.println("任务执行失败: " + e.getMessage());
        }
    }

    public void printSchedulerStats() {
        taskCondition.printStatistics();
    }

    private static class ScheduledTask {
        private final Runnable task;
        private final long executeTime;

        public ScheduledTask(Runnable task, long executeTime) {
            this.task = task;
            this.executeTime = executeTime;
        }

        public Runnable getTask() { return task; }
        public long getExecuteTime() { return executeTime; }
    }

    public static void main(String[] args) throws InterruptedException {
        TimedTaskScheduler scheduler = new TimedTaskScheduler();
        scheduler.start();

        // 调度几个任务
        scheduler.schedule(() -> System.out.println("任务1执行"), 1, TimeUnit.SECONDS);
        scheduler.schedule(() -> System.out.println("任务2执行"), 2, TimeUnit.SECONDS);
        scheduler.schedule(() -> System.out.println("任务3执行"), 3, TimeUnit.SECONDS);

        Thread.sleep(5000);
        scheduler.printSchedulerStats();
    }
}
